﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Aribaccio
{
    /// <summary>
    /// 周期任务线程
    /// 在调用 `Set` 方法后，所有等待线程都会被唤醒并继续执行，直到显式调用 `Reset` 方法将 ManualResetEvent 设置回无信号状态为止。即每次调用 `Set` 方法会唤醒所有等待线程。
    /// </summary>
    public class PeriodicTaskManual
    {
        /// <summary>
        /// 名称
        /// </summary>
        protected string Name { get; set; }
        /// <summary>
        /// 线程间隔休眠时间，单位：ms
        /// </summary>
        protected int IntervalSleep { get; set; }
        /// <summary>
        /// 线程对象
        /// </summary>
        protected Thread ThreadHandle { get; set; }
        /// <summary>
        /// 委托执行行为函数
        /// </summary>
        protected Action ExecAction { get; set; }
        /// <summary>
        /// 通知正在等待的线程已发生事件(暂停一下)
        /// </summary>
        protected ManualResetEvent ResetEventWait { get; set; }
        /// <summary>
        /// 通知正在等待的线程已发生事件(表示睡眠时间)
        /// </summary>
        protected ManualResetEvent ResetEventSleep { get; set; }
        /// <summary>
        /// 向应该被取消的 线程标记 发送信号（退出线程）
        /// </summary>
        protected CancellationTokenSource CancelToken { get; set; }

        /// <summary>
        /// 任务是否运行
        /// </summary>
        public bool IsRunning { get; protected set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="argName">线程任务名称</param>
        /// <param name="argIntervalSleep">线程间隔休眠时间(单位：ms)</param>
        /// <param name="argExecAction">委托执行行为函数</param>
        /// <param name="argIsStart">是否立即启动线程</param>
        /// <param name="argIsActive">是否立即激活线程</param>
        public PeriodicTaskManual(string argName, int argIntervalSleep, Action argExecAction, bool argIsStart = false, bool argIsActive = false)
        {
            this.Name = argName;
            this.ExecAction = argExecAction;
            this.IntervalSleep = argIntervalSleep;
            this.CancelToken = new CancellationTokenSource();
            this.ResetEventWait = new ManualResetEvent(false);
            this.ResetEventSleep = new ManualResetEvent(false);
            this.ThreadHandle = new Thread(ExecuteThreadHandle) { Name = this.Name, IsBackground = true };
            if (argIsStart) Start(argIsActive);
        }

        /// <summary>
        /// 启动线程
        /// </summary>
        /// <param name="argIsActive">是否立即激活线程</param>
        /// <returns></returns>
        public virtual Result Start(bool argIsActive = false)
        {
            Result ResultData = new Result();
            try
            {
                if (this.ThreadHandle == null)
                {
                    ResultData.ResultCode = ResultStatus.Failure;
                    ResultData.ResultMsg = $"{this.Name} => 启动失败，任务已被退出";
                    return ResultData;
                }
                if (!this.IsRunning)
                {
                    this.ThreadHandle.Start();
                    this.IsRunning = true;
                    ResultData.ResultMsg = $"{this.Name} => 任务已启动！";
                }
                if (argIsActive)
                {
                    this.Active();
                }
            }
            catch (Exception ep)
            {
                ResultData.ResultCode = ResultStatus.Exception;
                ResultData.ResultMsg = $"{this.Name} => 启动异常：" + ep.Message;
            }
            return ResultData;
        }

        /// <summary>
        /// 停止线程
        /// </summary>
        public virtual Result Stop()
        {
            Result ResultData = new Result();
            try
            {
                this.CancelToken.Token.Register(() => { ResultData.ResultMsg = $"{this.Name} => 任务已停止"; });
                //quit
                this.CancelToken.Cancel();
                this.IsRunning = false;
                //do not sleep
                this.ResetEventSleep.Set();
                //do not pause
                this.ResetEventWait.Set();            
            }
            catch (Exception ep)
            {
                ResultData.ResultCode = ResultStatus.Exception;
                ResultData.ResultMsg = $"{this.Name} => 停止异常：" + ep.Message;
            }
            return ResultData;
        }

        /// <summary>
        /// 激活线程
        /// </summary>
        public virtual void Active()
        {
            this.ResetEventWait.Set();
        }

        /// <summary>
        /// 暂停线程
        /// </summary>
        public virtual void Pause()
        {
            this.ResetEventWait.Reset();
        }

        /// <summary>
        /// 线程执行函数
        /// </summary>
        protected void ExecuteThreadHandle()
        {
            while (!CancelToken.IsCancellationRequested)
            {
                this.ResetEventWait.WaitOne();
                if (CancelToken.IsCancellationRequested) break;
                try
                {
                    this.ExecAction();
                }
                catch (ThreadAbortException) { break; }
                catch (Exception)
                {
                    //LOG.Write(ex);
                }
                this.ResetEventSleep.WaitOne(this.IntervalSleep);
            }
        }
    }
}
